function yWin ( p /* DOM parent (document.body) */ ) {
/*
    yWin 1.1; basic windows operation
    Copyright (C) 2008-2009  Yuriy Butenko

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
	var copyProp = function (s,d) {
		for ( var i in s ) d[i] = s[i];
	};
	var pCtxt = this, ctxt = this;
	var lStack = null;
	var winDiv = document.createElement("div");	// parent of all windows and lockDiv;
	winDiv.className = "yWin_WinDiv";
	var lockDiv = document.createElement("div");	// lock div;
	lockDiv.className = "yWin_LockDiv";
	lockDiv.style.display = "none";
	lockDiv.onclick = function (e) {
		if ( lStack && ( 'onlockclick' in lStack.e ) ) lStack.e.onlockclick( e || window.event );
		ctxt.stopPropagation(e);
	};
	lockDiv.onmousemove = function (e) {
		try{
		if ( lStack && ( 'onlockmousemove' in lStack.e ) ) lStack.e.onlockmousemove( e || window.event );
		} catch (e) { alert(lStack); };
		ctxt.stopPropagation(e);
	};
	winDiv.appendChild(lockDiv);
	p.appendChild( winDiv );
	winDiv.onclick = this.stopPropagation = function ( e ) {	// onclick set only; if attachEvent then e != null
		if ( e ) e.stopPropagation();
		else window.event.cancelBubble = true;
	};
	if ( this.isIE ) {
		var f1 = function () {
			winDiv.style.left = p.scrollLeft + "px";
			winDiv.style.top = p.scrollTop + "px";
		};
		var f2 = function () {
			lockDiv.style.width = p.clientWidth + "px";
			lockDiv.style.height = p.clientHeight + "px";
		};
		window.attachEvent("onscroll",f1);
		window.attachEvent("onresize",f2);
		f1();
		f2();
	};
	var dragOnMouseMove = function (e) {
		var x = lStack.e.drag, z = x.onDrag;
		if ( x.onDrag )
			x.onDrag.call( x.obj, x.x0, x.y0, "clientX" in e ? e.clientX : e.pageX, "clientY" in e ? e.clientY : e.pageY );
	};
	var dragOnClick = function (e) {
		var x = lStack.e.drag;
		if ( x.onStop ) x.onStop.call( x.obj, ( e || window.event ).ctrlKey );
		ctxt.unlock(x.h);
	};
	this.drag =	function (obj,e,onDrag,onStop) {	// obj - object; onDrag,onStop - callback functions; e - event; return - void;
		var h = {
			"drag":{
				"obj":obj,
				"onDrag":onDrag,
				"onStop":onStop,
				"h":null
			},
			"onlockmousemove":dragOnMouseMove,
			"onlockclick":dragOnClick
		};
		h.drag.x0 = e?e.pageX:window.event.clientX;
		h.drag.y0 = e?e.pageY:window.event.clientY;
		h.drag.h = this.lock( h );
	};
	this.lock = function (e,eDOM) {	// e - object; eDOM - DOM object; return - handle;
		if ( lStack ) {
			if ( lStack.eDOM ) lStack.eDOM.style.zIndex = 1;
		} else {
			lockDiv.style.display = "";
		};
		if ( eDOM ) eDOM.style.zIndex = 3;
		lStack = {"e":e,"p":null,"n":lStack,"eDOM":eDOM};
		if ( lStack.n ) lStack.n.p = lStack;
		return lStack;
	};
	this.unlock = function (h) {	// h - handle; return - void;
		if ( h == lStack ) {
			if ( h.eDOM ) h.eDOM.style.zIndex = 1;
			if ( lStack = h.n ) {
				h.n.p = null;
				if ( h.n.eDOM ) h.n.eDOM.style.zIndex = 3;
			} else {
				lockDiv.style.display = "none";
			};
		} else {
			h.p.n = h.n;
			if ( h.n ) h.n.p = h.p;
		};
		h.n = h.p = h.e = null;
	};
	this.button = function () {
		ctxt.buttonPrototype.call(this);
		this.e.className = "yWin_Button";
		this.e.innerHTML = '<span class="yWin_ButtonInner"></span>';
		this.content = this.e.firstChild;
	};
	this.button.prototype = this._buttonPrototype;
	this.radioButton = function () {
		ctxt.buttonPrototype.call(this);
		this.e.className = "yWin_RadioButton";
	};
	this.radioButton.prototype = this._buttonPrototype;
	this.buttonPrototype = function () {
		this.e = document.createElement("a");
		this.e.setAttribute("href","");
		var ctxt = this;
		this.e.onclick = function ( e ) {
			ctxt[ctxt._pressed ? 'setOff' : 'setOn']();
			if ( "onclick" in ctxt ) setTimeout(function(){ ctxt.onclick( e ); }, 0);
			return false;
		};
	};
	this.buttonPrototype.prototype = this._buttonPrototype;
	this.win = function () {
		this.e = document.createElement("div");
		this.e.className = "yWin_Win";
		this.e.innerHTML = '<div class="yWin_WinShadowCorner"></div>' +//0
			'<div class="yWin_WinShadowBottom"></div>'+	//1
			'<div class="yWin_WinShadowRight"></div>'+	//2
			'<div class="yWin_WinBorder"></div>'+		//3
			'<div class="yWin_WinHeader"></div>'+		//4
			'<div class="yWin_WinFooter"></div>'+		//5
			'<div class="yWin_WinContent"></div>'+		//6
			'<div class="yWin_WinCaption">My Window</div>'+//7
			'<a class="yWin_closeBtn" href=""></a>'+	//8
			'<div class="yWin_WinResizeT"></div>'+		//9
			'<div class="yWin_WinResizeB"></div>'+		//10 eval bottom property
			'<div class="yWin_WinResizeL"></div>'+		//11
			'<div class="yWin_WinResizeR"></div>'+		//12 eval right property
			'<div class="yWin_WinResizeTL"></div>'+		//13
			'<div class="yWin_WinResizeTR"></div>'+		//14 eval right property
			'<div class="yWin_WinResizeBL"></div>'+		//15 eval bottom property
			'<div class="yWin_WinResizeBR"></div>'+		//16 eval bottom&right property
			'<div class="yWin_WinResizeLT"></div>'+		//17
			'<div class="yWin_WinResizeLB"></div>'+		//18 eval bottom property
			'<div class="yWin_WinResizeRT"></div>'+		//19 eval right property
			'<div class="yWin_WinResizeRB"></div>';		//20 eval bottom&right property
		//if ( pCtxt.isIE ) for ( var i = 0; i < 3; i++ ) this.e.childNodes[i].className += 'IE';
		var ctxt = this;
		this.e.childNodes[8].onclick = function () {
			window.setTimeout( function () { ctxt.close(); }, 0 );
			return false;
		};
		this.e.childNodes[7].onclick = function (e) {	//winCaption
			ctxt.oldLeft = ctxt.left;
			ctxt.oldTop = ctxt.top;
			pCtxt.drag(ctxt,e,ctxt.onDrag);
		};
		for ( var i = 9; i <= 20; i++ ) this.e.childNodes[i].onclick = function (e) {
				ctxt.oldLeft = ctxt.left;
				ctxt.oldTop = ctxt.top;
				ctxt.oldWidth = ctxt.width;
				ctxt.oldHeight = ctxt.height;
				ctxt.resizeMode = this.className.substr("yWin_WinResize".length);
				pCtxt.drag(ctxt,e,ctxt.onResize);
			};
		this.e.style.position = "absolute";
		this.e.style.display = "none";
		this.content = this.e.childNodes[6];
		this.e.onclick = function ( e ) {
			if ( ctxt.e.nextSibling ) {
				ctxt.e.parentNode.appendChild( ctxt.e.parentNode.removeChild( ctxt.e ) );
			};
			pCtxt.stopPropagation( e );
		};
		this.e.onmousemove = pCtxt.stopPropagation;
		winDiv.appendChild(this.e);
	};
	copyProp(this.posFlavour,this.win.prototype);
	copyProp(this._winProp,this.win.prototype);
}
yWin.prototype = {
"isIE":navigator.userAgent.indexOf( "MSIE" ) != -1 && navigator.userAgent.indexOf( "opera" ) == -1,
"lock":null,	//function (e)  {}; e - object; return - handle;
"unlock":null,	//function (h)  {}; h - handle; return - void;
"drag":null,	//function (obj,e,onDrag,onStop) {}; obj - object; onDrag,onStop - callback functions!; e - event; return - void;
"win":null,	//constructor
"button":null,	// button constructor
"posFlavour": {
	"left":0,
	"top":0,
	"width":32,
	"height":32,
	"setPos":function ( left, top ) { 
		this.e.style.left = ( this.left = left ) + "px";
		this.e.style.top = ( this.top = top ) + "px";
	},
	"setDim":function ( width, height ) {
		this.e.style.width = ( this.width = width ) + "px";
		this.e.style.height = ( this.height = height ) + "px";
	}
},
"_setPos":function(caption,w,width){
	w.setCaption(caption);
	w.autoheight = true;
	w.on();
	w.up();
	var wwidth = window.innerWidth || document.body.clientWidth;
	w.setDim(Math.min( width || wwidth >> 1, wwidth),0);
	w.setPos( w.centerX(), w.centerY() );
},
"alert":	function ( caption, msg, obj, callback, width ) {	//this function is not constructor
	var z = new this.win();
	var h = this.lock( z, z.e );
	z.content.innerHTML = '<div style="text-align:center;margin:15px 25px;">'+msg+'</div>'
		+'<div class="yWin_ButtonContainer" style="text-align:center;margin:15px 25px 8px 25px;">&nbsp;</div>';
	var b = new this.button();
	b.content.innerHTML = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
	z.content.childNodes[1].replaceChild(b.e,z.content.childNodes[1].firstChild);	// childNodes for IE :)
	z.resize = false;
	z.setResize();
	var ctxt = this;
	b.onclick = z.close = function () {
		callback && callback.call(obj);
		ctxt.unlock(h);
		ctxt.win.prototype.close.call(z);
	};
	this._setPos(caption,z,width);
},
"confirm":	function ( caption, msg, obj, callback, width ) {	//this function is not constructor
	var z = new this.win();
	var h = this.lock( z, z.e );
	z.content.innerHTML = '<div style="text-align:center;margin:15px 25px;">'+msg+'</div>'
		+'<div class="yWin_ButtonContainer" style="text-align:center;margin:15px 25px 8px 25px;"></div>';
	var yes = new this.button(), no = new this.button();
	yes.content.innerHTML = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Yes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
	z.content.lastChild.appendChild( yes.e );
	no.content.innerHTML = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;No&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
	z.content.lastChild.appendChild( no.e );
	z.resize = false;
	z.setResize();
	var ctxt = this;
	yes.onclick = no.onclick = z.close = function () {
		callback && callback.call( obj, this == yes );
		ctxt.unlock(h);
		ctxt.win.prototype.close.call(z);
	};
	this._setPos(caption,z,width);
},
"prompt":	function ( caption, msg, val, obj, callback, width ) {	//this function is not constructor
	var z = new this.win();
	var h = this.lock( z, z.e );
	z.content.innerHTML = '<div style="text-align:center;margin:15px 25px;">'+msg+'</div>'+
		'<div style="text-align:center;margin:15px 25px;"><input style="width:80%;" /></div>'+
		'<div class="yWin_ButtonContainer" style="text-align:center;margin:15px 25px 8px 25px;"></div>';
	var inp = z.content.firstChild.nextSibling.firstChild;
	var ok = new this.button(), cncl = new this.button();
	ok.content.innerHTML = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OK&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
	z.content.lastChild.appendChild( ok.e );
	cncl.content.innerHTML = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cancel&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
	z.content.lastChild.appendChild( cncl.e );
	z.resize = false;
	z.setResize();
	var ctxt = this;
	var f = ok.onclick = cncl.onclick = z.close = function () {
		callback && callback.call( obj, this == ok ? inp.value : null );
		ctxt.unlock(h);
		ctxt.win.prototype.close.call(z);
	};
	inp.onkeydown = function (e) { if ( ( e || window.event).keyCode == 13 ) f.call(ok); };
	this._setPos(caption,z,width);
	inp.value = inp.defaultValue = val;	// IE have not defaultValue?
	inp.select();
	inp.focus();
},
"_winProp":{
	"del":function () {
		this.e.parentNode.removeChild(this.e);
		this.e = null;
	},
	"on":function () {
		this.e.style.display = "";
	},
	"off":function () {
		this.e.style.display = "none";
	},
	"up":function () {
		var p = this.e.parentNode;
		p.removeChild( this.e );
		p.appendChild( this.e );
	},
	"close":function () {
		this.del();
	},
	"onDrag":function ( x0, y0, xn, yn ) {
		this.setPos( this.oldLeft + xn - x0, this.oldTop + yn - y0 );
	},
	"minWidth":40,
	"minHeight":32,
	"resize":true,	// true, "horizontal", "vertical"
	"setResize":function () {
		for ( var v = this.resize=="true"?"":"none", s = this.e.childNodes[9], i = 9; i <= 20; i++, s = s.nextSibling ) s.style.display = v;
		if ( this.resize == "horizontal" ) this.e.childNodes[11].style.display = this.e.childNodes[12].style.display = "";
		if ( this.resize == "vertical" ) this.e.childNodes[9].style.display = this.e.childNodes[10].style.display = "";
	},
	"resizeMode":"",
	"onResize":function ( x0, y0, x1, y1 ) {
		var width = this.width, height = this.height, dX = x1 - x0, dY = y1 - y0;
		if ( this.resizeMode.indexOf("T") > -1 ) {
			if ( this.oldHeight - dY < this.minHeight ) dY = this.oldHeight - this.minHeight;
			this.setPos( this.left, this.oldTop + dY );
			height = this.oldHeight - dY;
		} else if ( this.resizeMode.indexOf("B") > -1 ) {
			if ( this.oldHeight + dY < this.minHeight ) dY = this.minHeight - this.oldHeight;
			height = this.oldHeight + dY;
		};
		if ( this.resizeMode.indexOf("L") > -1 ) {
			if ( this.oldWidth - dX < this.minWidth ) dX = this.oldWidth - this.minWidth;
			this.setPos( this.oldLeft + dX, this.top );
			width = this.oldWidth - dX;
		} else if ( this.resizeMode.indexOf("R") > -1 ) {
			if ( this.oldWidth + dX < this.minWidth ) dX = this.minWidth - this.oldWidth;
			width = this.oldWidth + dX;
		};
		this.setDim( width, height );
	},
	"setDim":function ( width, height ) {
		var x = this.e.style;
		x.width = ( this.width = width ) + "px";
		this.height = height;
		if ( this.autoheight ) {
			var z = this.e.childNodes[6];
			z.style.height = "";	// content
			this.height = z.offsetHeight + z.offsetTop + 4;
		};
		var h = Math.max( this.minHeight || 32, this.height );
		x.height = h + "px";
		x = this.e.childNodes;
		x[3].style.width = this.width - 2 + "px";
		x[3].style.height = h - ( yWin.prototype.isIE ? 0 : 2 ) + "px";
		x[5].style.top = h - 4 + "px";
		x[6].style.height = h - 31 + "px";
		x[7].style.width = this.width - ( yWin.prototype.isIE ? 6 : 6 + 24 ) + "px";
		x[10].style.top = x[15].style.top = x[16].style.top = h - 3 + "px";
		x[18].style.top = x[20].style.top = h - 16 + "px";
		x[14].style.left = x[16].style.left = this.width - 16 + "px";
		x[12].style.left = x[19].style.left = x[20].style.left = this.width - 3 + "px";
		x[1].style.top = this.height + "px";
		x[0].style.left = x[1].style.width = this.width - 4 + "px";	// 8x8 - 12x12
		x[2].style.left = this.width + "px";
		x[0].style.top = x[2].style.height = this.height - 4 + "px";	// 8x8 - 12x12
	},
	"content":null,
	"autoheight":false,
	"onlockmousemove":function () {},
	"onlockclick":function () {},
	"centerX":function () {
		return ( window.innerWidth || document.body.clientWidth ) - this.width >> 1;
	},
	"centerY":function () {
		return ( window.innerHeight || document.body.clientHeight ) - this.height >> 1;
	},
	"setCaption":function ( c ) {
		this.e.childNodes[7].innerHTML = c || "\u00a0";
	}
},
"_buttonPrototype":{
	"onclick":function () {},
	"content":null,
	"getPressed":function () { return this._pressed; },
	"setOn":function () {
		this._pressed = true;
		if ( this.e.className.indexOf("Pressed") == -1 ) this.e.className += "Pressed"; 
	},
	"setOff":function () {
		this._pressed = false;
		this.e.className = this.e.className.replace("Pressed", "");
	},
	"_pressed":false
}
};
